﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using Medianamik.Core;
using SubSonic;

namespace Medianamik.Client.MVP.Model.DataAccess
{
    public abstract class MedianamikRepositoryBase<TConcreteTypeCollection, TConcreteType, TInterface> : NodeRepository
        where TConcreteTypeCollection : ICollectionWithChildren<TConcreteTypeCollection, TConcreteType>, new()
        where TConcreteType : IRecordBase, new()
    {
        public IEnumerable<TInterface> GetWithFilters(ContentState contentState, Guid? typeId, Guid? parentId, 
            IEnumerable<Where> wheres, IEnumerable<BetweenAnd> betweensAnd, string orderByString)
        {
            var query = new Query(new TConcreteType().GetSchema());


            query.AddWhere("Generation", (int)contentState);

            if (parentId.HasValue)
            {
                query.AddWhere("ParentNodeId", parentId.Value.ToString());
            }

            if (typeId.HasValue)
            {
                query.AddWhere("TypeId", typeId.Value.ToString());
            }

            if (wheres != null)
            {
                for (var i = 0; i < wheres.Count(); i++)
                {
                    query.AddWhere(wheres.ElementAt(i));
                }
            }

            if (betweensAnd != null)
            {
                for (var i = 0; i < betweensAnd.Count(); i++)
                {
                    query.AddBetweenAnd(betweensAnd.ElementAt(i));
                }
            }

            if (!string.IsNullOrEmpty(orderByString))
            {
                query.OrderByCollection = new OrderByCollection();
                query.ORDER_BY(orderByString);
            }

            var publications = new TConcreteTypeCollection();
            publications.LoadAndCloseReader(query.ExecuteReader());
            return publications.Cast<TInterface>();
        }

        public PagedCollection<TInterface> PagedWithFilters(ContentState contentState,
           int pageIndex, int pageSize, Guid? typeId, Guid? parentId, IEnumerable<Where> wheres,
           IEnumerable<BetweenAnd> betweensAnd, string orderByString)
        {
            if (pageIndex == 0)
                throw new Exception("PageIndex is a one-based index.");

            var query = new Query(new TConcreteType().GetSchema())
            {
                PageSize = pageSize,
                PageIndex = pageIndex
            };

            query.AddWhere("Generation", (int)contentState);

            if (parentId.HasValue)
            {
                query.AddWhere("ParentNodeId", parentId.Value.ToString());
            }

            if (typeId.HasValue)
            {
                query.AddWhere("TypeId", typeId.Value.ToString());
            }

            if (wheres != null)
            {
                for (var i = 0; i < wheres.Count(); i++)
                {
                    query.AddWhere(wheres.ElementAt(i));
                }
            }

            if (betweensAnd != null)
            {
                for (var i = 0; i < betweensAnd.Count(); i++)
                {
                    query.AddBetweenAnd(betweensAnd.ElementAt(i));
                }
            }

            if (!string.IsNullOrEmpty(orderByString))
            {
                query.OrderByCollection = new OrderByCollection();
                query.ORDER_BY(orderByString);
            }

            var publications = new TConcreteTypeCollection();
            publications.LoadAndCloseReader(query.ExecuteReader());

            return new PagedCollection<TInterface>(publications.Cast<TInterface>(),
                query.GetRecordCount());
        }

        public virtual IEnumerable<TInterface> ChildsOf(Guid nodeId, bool inclusive, int maxDepth, ContentState contentState)
        {
            return new TConcreteTypeCollection()
                .LoadChildNodes(nodeId, inclusive, maxDepth, contentState)
                .Cast<TInterface>();
        }

        public virtual IEnumerable<TInterface> ParentsOf(Guid nodeId, bool inclusive, int maxDepth, ContentState contentState)
        {
            return new TConcreteTypeCollection()
                .LoadParentNodes(nodeId, inclusive, maxDepth, contentState)
                .Cast<TInterface>();
        }

        public virtual IEnumerable<TInterface> All(ContentState contentState)
        {
            return new TConcreteTypeCollection().Load(contentState)
                .Cast<TInterface>();
        }
    }
}